using System;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;

namespace LineCountEngine
{
	public class DirectoryLineCounter : IComparable
	{
		public static string[] DirectoryIgnoreNames;
		public static string[] FileSearchPatterns;

		public DirectoryLineCounter( DirectoryInfo di )
		{
			this.Directory = di;
		}
		
		public DirectoryInfo Directory;
		public bool Recurse = true;
		public int DirectoryLines;
		public int SubDirectoriesTotalLines;
		public int TotalLines { get{ return DirectoryLines + SubDirectoriesTotalLines; } }

		public DirectoryLineCounter[] SubDirectoryCounters;
		public event FilesCompletedHandler FilesCompleted;

		public int filesToCount()
		{
			int fileCount = 0;
			foreach( string pattern in FileSearchPatterns )
			{
				 fileCount += Directory.GetFiles( pattern ).Length;
			}
			
			if( Recurse )
			{
				foreach( DirectoryInfo di in this.Directory.GetDirectories() )
				{
					bool searchDirectory = true;
					foreach( string ignoreName in DirectoryIgnoreNames )
					{
						if( di.Name.ToLower() ==  ignoreName.ToLower() )
						{
							searchDirectory = false;
							break;
						}
					}
					if( searchDirectory )
					{
						DirectoryLineCounter dlc = new DirectoryLineCounter( di );
						fileCount += dlc.filesToCount(); 
					}
				}
			}

			return fileCount;
		}

		public void countLines( )
		{
			DirectoryLines = countLines( this.Directory );
			SubDirectoriesTotalLines = 0;

			if( Recurse )
			{
				ArrayList directoryCounters = new ArrayList();

				foreach( DirectoryInfo di in this.Directory.GetDirectories() )
				{
					bool searchDirectory = true;
					foreach( string ignoreName in DirectoryIgnoreNames )
					{
						if( di.Name.ToLower() ==  ignoreName.ToLower() )
						{
							searchDirectory = false;
							break;
						}
					}
					if( searchDirectory )
					{
						DirectoryLineCounter dlc = new DirectoryLineCounter( di );
						dlc.FilesCompleted += new FilesCompletedHandler(dlc_FilesCompleted);
						dlc.countLines();
						directoryCounters.Add( dlc );
						SubDirectoriesTotalLines += (dlc.SubDirectoriesTotalLines + dlc.DirectoryLines);
					}
				}

				directoryCounters.Sort();

				SubDirectoryCounters = (DirectoryLineCounter[])directoryCounters.ToArray( typeof(DirectoryLineCounter) );
			}
		}

		protected int countLines( DirectoryInfo di )
		{
			int lines = 0;
			int filesDone = 0;
			foreach( string pattern in FileSearchPatterns )
			{
				FileInfo[] files = di.GetFiles( pattern );
				foreach( FileInfo fi in files )
				{
					lines += getFileLineCount( fi );
					filesDone++;
				}
			}
			OnFilesCompleted( filesDone );
			return lines;
		}

		protected void OnFilesCompleted( int filesCompleted )
		{
			if( FilesCompleted != null && filesCompleted != 0 )
				FilesCompleted( this, filesCompleted );
		}

		protected int getFileLineCount( FileInfo fi )
		{
			int lines = 0;
			try
			{
				StreamReader reader = fi.OpenText();
				while( reader.ReadLine() != null )
					lines++;
			}
			catch
			{
			}

			return lines;
		}

		private void dlc_FilesCompleted(object sender, int filesCompleted)
		{
			OnFilesCompleted( filesCompleted );
		}

		public int CompareTo(object obj)
		{
			DirectoryLineCounter other = obj as DirectoryLineCounter;
			if( other != null )
			{
				return -this.TotalLines.CompareTo( other.TotalLines );
			}
			return 0;
		}
	}

	public delegate void FilesCompletedHandler( object sender, int filesCompleted );
}
